unit uMain;

{$mode Delphi}{$H+}

interface

uses
  Classes, SysUtils, Forms, Controls, Graphics, Dialogs, ExtCtrls, ComCtrls,
  Menus, StdCtrls, Buttons, laz.VirtualTrees, SynEdit, Types, dbconnect, appTool,
  Generics.Collections, Generics.Defaults, RegExpr;

type

  { TFmMain }

  TFmMain = class(TForm)
    ControlBar1: TControlBar;
    MainImageList: TImageList;
    MasterTree: TLazVirtualStringTree;
    LargeImageList: TImageList;
    MainMenu1: TMainMenu;
    MenuSqlserver: TMenuItem;
    MenuItemFile: TMenuItem;
    MenuItemNewProject: TMenuItem;
    MenuItem2: TMenuItem;
    MenuItem3: TMenuItem;
    PageControl1: TPageControl;
    Panel1: TPanel;
    Panel2: TPanel;
    Panel4: TPanel;
    Panel5: TPanel;
    Panel6: TPanel;
    PopMNew: TPopupMenu;
    Splitter1: TSplitter;
    Splitter2: TSplitter;
    StatusBar1: TStatusBar;
    SynEdit1: TSynEdit;
    TabSheet1: TTabSheet;
    ToolBar1: TToolBar;
    ToolButton1: TToolButton;
    ToolButton2: TToolButton;
    procedure Button1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure MasterTreeGetNodeDataSize(Sender: TBaseVirtualTree;
      var NodeDataSize: integer);
    procedure MasterTreeGetText(Sender: TBaseVirtualTree; Node: PVirtualNode;
      Column: TColumnIndex; TextType: TVSTTextType; var CellText: string);
    procedure MasterTreeInitChildren(Sender: TBaseVirtualTree;
      Node: PVirtualNode; var ChildCount: cardinal);
    procedure MasterTreeInitNode(Sender: TBaseVirtualTree;
      ParentNode, Node: PVirtualNode; var InitialStates: TVirtualNodeInitStates);
    procedure MenuSqlserverClick(Sender: TObject);
    procedure SpeedButton1Paint(Sender: TObject);
  private
    FConnections: TDBConnectionList;

  public
    procedure ConnectionsNotify(Sender: TObject; constref Item: TDBConnection;
      Action: TCollectionNotification);


    property Connections: TDBConnectionList read FConnections;

  end;

var
  FmMain: TFmMain;

implementation

uses uapijk, uDataSource, ufmSqlserversourcset, dbstructures.mssql;

  {$R *.lfm}

  { TFmMain }

procedure TFmMain.Button1Click(Sender: TObject);
var
  lnret: int64;
  dbinfo: TMyDbinfo;
  ret: TResultInfo;
  //FLib: TMainLib;

  sqlhost: TSqlHost;
  SQLInfo: TResultArraySQLInfo;
  sqlhosts: array of PSqlHost;
  pphost: PPSqlHost;
  phost: PSqlHost;
  i: integer;
begin  //'127.0.0.1', 'sa', 'sql', 'master', lnret , 3688)
  dbinfo.server := '127.0.0.1';
  dbinfo.user := 'sa';
  dbinfo.paswd := 'sql';
  dbinfo.db := 'master';
  dbinfo.port := 3688;



  fillchar(sqlhost, sizeof(TSqlHost), 0);
  sqlhost.Host := '127.0.0.1';
  sqlhost.Name := '127.0.0.1';
  sqlhost.Port := 3688;
  sqlhost.Database := 'master';
  sqlhost.Password := 'sql';
  //sqlhost.user := '';  // user没有值赋值为空，record没有packed值时
  sqlhost.Databasetype := 1;
  //sqlhost.Remark:= '';
  sqlhost.Id := 0;
  qiuLib.DLStore(sqlhost, ret);
  ShowMessage(ret.strid + '  ' + ret.err);

  SQLInfo := qiuLib.DLAll();
  pphost := SQLInfo.sqlhosts;
  for i := 0 to SQLInfo.len - 1 do
  begin
    phost := pphost^;
    Inc(pphost);
    ShowMessage(phost.Host);
  end;

end;

procedure TFmMain.FormCreate(Sender: TObject);
var
  LibraryPath, DefaultLibrary: string;
begin
  DefaultLibrary := 'qiusql.dll';

  LibraryPath := ExtractFilePath(ParamStr(0)) + DefaultLibrary;
  qiuLib := TQiuLib.Create(LibraryPath, DefaultLibrary);
  //ret := FLib.GetSqlDbConn(dbinfo);
  //ShowMessage(ret.strid + '  ' + ret.err);
  qiuLib.InitCliModule;

  // Set up connections list
  FConnections := TDBConnectionList.Create;
  FConnections.OnNotify := ConnectionsNotify;
end;

procedure TFmMain.MasterTreeGetNodeDataSize(Sender: TBaseVirtualTree;
  var NodeDataSize: integer);
begin
  // Set pointer size of bound TDBObjects
  NodeDataSize := SizeOf(TDBObject);
end;

procedure TFmMain.MasterTreeGetText(Sender: TBaseVirtualTree;
  Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType;
  var CellText: string);
var
  DBObjects: TDBObjectList;
  DBObj: PDBObject;
  i: integer;
  Bytes: int64;
  AllListsCached: boolean;
begin
  DBObj := Sender.GetNodeData(Node);
  case Column of
    0: case DBObj.NodeType of
        lntNone:
        begin
          CellText := DBObj.Connection.Parameters.SessionName;
        end;
        lntDb: CellText := DBObj.Database;
        lntGroup: begin
          CellText := DBObj.Name;
          if Sender.ChildrenInitialized[Node] then
            CellText := CellText + ' (' + FormatNumber(Sender.ChildCount[Node]) + ')';
        end;
        lntTable..lntEvent:
        try
          if (DBObj.Schema <> '') and (DBObj.Connection.Parameters.NetTypeGroup =
            ngMSSQL) then
            CellText := DBObj.Schema + '.' + DBObj.Name
          else
            CellText := DBObj.Name;
        except
          CellText := DBObj.Name;
        end;
        lntColumn: CellText := DBObj.Column;
      end;
    1: if DBObj.Connection.Active then case DBObj.NodeType of
          // Calculate and display the sum of all table sizes in ALL dbs if all table lists are cached
          lntNone: begin
            AllListsCached := True;
            for i := 0 to DBObj.Connection.AllDatabases.Count - 1 do
            begin
              if not DBObj.Connection.DbObjectsCached(
                DBObj.Connection.AllDatabases[i]) then
              begin
                AllListsCached := False;
                break;
              end;
            end;
            // Will be also set to a negative value by GetTableSize and results of SHOW TABLES
            Bytes := -1;
            if AllListsCached then
            begin
              Bytes := 0;
              for i := 0 to DBObj.Connection.AllDatabases.Count - 1 do
              begin
                DBObjects := DBObj.Connection.GetDBObjects(
                  DBObj.Connection.AllDatabases[i]);
                Inc(Bytes, DBObjects.DataSize);
              end;
            end;
            if Bytes >= 0 then CellText := FormatByteNumber(Bytes)
            else
              CellText := '';
          end;
          // Calculate and display the sum of all table sizes in ONE db, if the list is already cached.
          lntDb: begin
            if not DBObj.Connection.DbObjectsCached(DBObj.Database) then
              CellText := ''
            else
            begin
              DBObjects := DBObj.Connection.GetDBObjects(DBObj.Database);
              CellText := FormatByteNumber(DBObjects.DataSize);
            end;
          end;
          lntTable: begin
            if DBObj.Size >= 0 then
              CellText := FormatByteNumber(DBObj.Size)
            else
              CellText := '';
          end
          else
            CellText := ''; // Applies for views/procs/... which have no size
        end;
  end;
end;

procedure TFmMain.MasterTreeInitChildren(Sender: TBaseVirtualTree;
  Node: PVirtualNode; var ChildCount: cardinal);
var
  DBObj: PDBObject;
  Columns: TTableColumnList;
  DBObjects: TDBObjectList;
begin
  DBObj := Sender.GetNodeData(Node);
  case DBObj.NodeType of
    // Session node expanding
    lntNone: begin
      Screen.Cursor := crHourglass;
      //ShowStatusMsg(_('Reading Databases...'));
      if Sender.Tag = VTREE_NOTLOADED_PURGECACHE then
        DBObj.Connection.RefreshAllDatabases;
      //ShowStatusMsg;
      Sender.Tag := VTREE_LOADED;
      //InvalidateVT(ListDatabases, VTREE_NOTLOADED, True);    //ListDatabases
      ChildCount := DBObj.Connection.AllDatabases.Count;
      Screen.Cursor := crDefault;
    end;
    // DB node expanding
    lntDb: begin
      if True then
      begin    //if actGroupObjects.Checked then begin
        // Just tables, views, etc.
        ChildCount := 6;
      end
      else
      begin
        //ShowStatusMsg(_('Reading objects ...'));
        Screen.Cursor := crHourglass;
        try
          ChildCount := DBObj.Connection.GetDBObjects(
            DBObj.Connection.AllDatabases[Node.Index]).Count;
        finally
          //ShowStatusMsg;
          Screen.Cursor := crDefault;
        end;
      end;
    end;
    lntGroup: begin
      ChildCount := 0;
      DBObjects := DBObj.Connection.GetDBObjects(DBObj.Database,
        False, DBObj.GroupType);
      ChildCount := DBObjects.Count;
    end;
    lntTable:
    begin
      //if GetParentFormOrFrame(Sender) is TfrmSelectDBObject then begin
      //  Columns := DBObj.TableColumns;
      //  ChildCount := Columns.Count;

    end;
  end;
end;

procedure TFmMain.MasterTreeInitNode(Sender: TBaseVirtualTree;
  ParentNode, Node: PVirtualNode; var InitialStates: TVirtualNodeInitStates);
var
  Item, ParentObj: PDBObject;
  DBObjects: TDBObjectList;
  Columns: TTableColumnList;
begin
  Item := Sender.GetNodeData(Node);
  if (not Assigned(ParentNode)) or (ParentNode = nil) then
  begin
    Item^ := TDBObject.Create(FConnections[Node.Index]);
    //// Ensure plus sign is visible for root (and dbs, see below)
    Include(InitialStates, ivsHasChildren);
  end;

end;

procedure TFmMain.MenuSqlserverClick(Sender: TObject);
var
  connectParameters: TConnectionParameters;
  sqlhost: TSqlHost;
  ret: TResultInfo;
  Node: PVirtualNode;
  Connection: TDBConnection;
  Item, ParentObj: PDBObject;
begin
  FmSQLServerSet := TFmSQLServerSet.Create(self);
  FmSQLServerSet.isNew := True;
  if FmSQLServerSet.ShowModal = mrOk then
  begin
    if FmSQLServerSet.isNew then
    begin
      connectParameters := TConnectionParameters.Create;
      connectParameters.id := 0;
    end;
    connectParameters.Hostname := FmSQLServerSet.EDHost.Text;
    connectParameters.Port := FmSQLServerSet.SpinEditPort.Value;
    connectParameters.WindowsAuth :=
      integer(FmSQLServerSet.CBAuthentication.Items.Objects[
      FmSQLServerSet.CBAuthentication.ItemIndex]) = Ord(sqlAuthWindows);
    connectParameters.SSHActive :=
      FmSQLServerSet.chkSSHActive.Enabled and FmSQLServerSet.chkSSHActive.Checked;
    connectParameters.SSHExe := FmSQLServerSet.comboSSHExe.Text;
    connectParameters.SSHHost := FmSQLServerSet.editSSHhost.Text;
    connectParameters.SSHPort := MakeInt(FmSQLServerSet.editSSHport.Text);
    connectParameters.SSHUser := FmSQLServerSet.editSSHUser.Text;
    connectParameters.SSHPassword := FmSQLServerSet.editSSHPassword.Text;
    connectParameters.SSHTimeout := FmSQLServerSet.updownSSHTimeout.Position;
    connectParameters.SSHPrivateKey := FmSQLServerSet.editSSHPrivateKey.Text;
    connectParameters.SSHLocalPort := MakeInt(FmSQLServerSet.editSSHlocalport.Text);
    connectParameters.WantSSL := FmSQLServerSet.chkWantSSL.Checked;
    connectParameters.SSLPrivateKey := FmSQLServerSet.editSSLPrivateKey.Text;
    connectParameters.SSLCertificate := FmSQLServerSet.editSSLCertificate.Text;
    connectParameters.SSLCACertificate := FmSQLServerSet.editSSLCACertificate.Text;
    connectParameters.SSLCipher := FmSQLServerSet.editSSLCipher.Text;
    connectParameters.NetTypeGroup := ngMSSQL;
    connectParameters.SessionName := FmSQLServerSet.EdConnectName.Text;
    connectParameters.InitDataBase := FmSQLServerSet.EdDatabase.Text;

    fillchar(sqlhost, sizeof(TSqlHost), 0);
    sqlhost.Host := pansichar(connectParameters.Hostname);
    sqlhost.Name := pansichar(connectParameters.SessionName);
    sqlhost.Port := connectParameters.Port;
    sqlhost.Database := pansichar(connectParameters.InitDataBase);
    sqlhost.Password := pansichar(connectParameters.Password);
    //sqlhost.user := '';  // user没有值赋值为空，record没有packed值时
    sqlhost.Databasetype := Ord(connectParameters.NetTypeGroup);
    //sqlhost.Remark:= '';
    sqlhost.Id := connectParameters.Id;
    qiuLib.DLStore(sqlhost, ret);
    if ret.err = 'nil' then
    begin
      connectParameters.Id := StrToInt(ret.strid);
      Connection := connectParameters.CreateConnection(self);
      //Connection.OnLog := LogSQL;
      //Connection.OnConnected := ConnectionReady;
      //Connection.OnDatabaseChanged := DatabaseChanged;
      //Connection.OnObjectnamesChanged := ObjectnamesChanged;

      FConnections.Add(Connection);
      //Node := MasterTree.AddChild(nil);
      //Item := MasterTree.GetNodeData(Node);

      //Item^ := TDBObject.Create(Connection);
      SynEdit1.Lines.Add(ret.err);
      qiuLib.FreeResultInfo(ret);

      SynEdit1.Lines.Add('--------------------');
      SynEdit1.Lines.Add(ret.err);


      //Node.Data;
    end;
    //ret.

  end;
  FreeAndNil(FmSQLServerSet);
end;

procedure TFmMain.SpeedButton1Paint(Sender: TObject);
var
  SpeedButton: TSpeedButton;
  ArrowWidth, ArrowHeight: integer;
  ArrowRect: TRect;
  Points: array of TPoint;
begin
  //SpeedButton := Sender as TSpeedButton;
  //ArrowWidth := 10; // 箭头的宽度
  //ArrowHeight := 5; // 箭头的高度

  //// 绘制SpeedButton本身
  ////SpeedButton.Canvas.Brush.Color := clBtnFace;
  ////SpeedButton.Canvas.FillRect(SpeedButton.ClientRect);
  ////SpeedButton.Canvas.Brush.Style := bsClear;
  ////SpeedButton.Canvas.TextOut(2, 2, SpeedButton.Caption);

  //// 绘制箭头
  //ArrowRect.Left := SpeedButton.Width - ArrowWidth;
  //ArrowRect.Top := (SpeedButton.Height - ArrowHeight) div 2;
  //ArrowRect.Right := SpeedButton.Width;
  //ArrowRect.Bottom := ArrowRect.Top + ArrowHeight;

  //SpeedButton.Canvas.Pen.Color := clBlack;
  //with SpeedButton.Canvas do
  //begin
  //  setlength(Points,3);
  //  points[0] :=  Point(ArrowRect.Left, ArrowRect.Top);
  //  points[1] :=  Point(ArrowRect.Left + ArrowWidth div 2, ArrowRect.Top + ArrowHeight);
  //  points[2] :=  Point(ArrowRect.Right, (ArrowRect.Top + ArrowRect.Bottom) div 2);
  //  Polygon(points);
  //end;
end;

procedure TFmMain.ConnectionsNotify(Sender: TObject; constref Item: TDBConnection;
  Action: TCollectionNotification);
var
  Results: TDBQuery;
  //Tab: TQueryTab;
  //ResultTab: TResultTab;
  i: integer;
  Keys, NamesInKey: TStringList;
  rx: TRegExpr;
  ForceDeleteTableKey: boolean;
begin
  // Connection removed or added
  case Action of
    cnRemoved, cnExtracted: begin
      // Post pending UPDATE and release current table with result
      //Results := GridResult(DataGrid);
      //if Assigned(Results) then begin
      //  if Results.Modified then
      //    actDataPostChangesExecute(DataGrid);
      //  if DataGridResult = Results then begin
      //    FreeAndNil(DataGridResult);
      //    DataGridTable := nil;
      //  end;
      //end;

      //// Remove result sets which may cause AVs when disconnected
      //for Tab in QueryTabs do begin
      //  if Assigned(Tab.QueryProfile) and (Tab.QueryProfile.Connection = Item) then
      //    FreeAndNil(Tab.QueryProfile);
      //  for ResultTab in Tab.ResultTabs do begin
      //    if ResultTab.Results.Connection = Item then begin
      //      Tab.ResultTabs.Clear;
      //      Tab.tabsetQuery.Tabs.Clear;
      //      break;
      //    end;
      //  end;
      //end;
      //for i:=0 to FHostListResults.Count-1 do begin
      //  if (FHostListResults[i] <> nil) and (FHostListResults[i].Connection = Item) then begin
      //    FHostListResults[i].Free;
      //    FHostListResults[i] := nil;
      //  end;
      //end;

      //// Remove table keys if unwanted or empty
      //ForceDeleteTableKey := not AppSettings.ReadBool(asReuseEditorConfiguration);
      //AppSettings.SessionPath := Item.Parameters.SessionPath;
      //Keys := AppSettings.GetKeyNames;
      //rx := TRegExpr.Create;
      //rx.Expression := '.+'+QuoteRegExprMetaChars(DELIM)+'.+';
      //for i:=0 to Keys.Count-1 do begin
      //  if rx.Exec(Keys[i]) then begin
      //    AppSettings.SessionPath := Item.Parameters.SessionPath + '\' + Keys[i];
      //    NamesInKey := AppSettings.GetValueNames;
      //    if (NamesInKey.Count = 0) or ForceDeleteTableKey then begin
      //      AppSettings.DeleteCurrentKey;
      //    end;
      //  end;
      //end;
      //rx.Free;

      //FreeAndNil(ActiveObjectEditor);
      //RefreshHelperNode(TQueryTab.HelperNodeProfile);
      //RefreshHelperNode(TQueryTab.HelperNodeColumns);

      // Last chance to access connection related properties before disconnecting

      // Disconnect
      Item.Active := False;
    end;

    // New connection
    cnAdded: masterTree.InsertNode(masterTree.GetLastChild(nil), amInsertAfter);
  end;
end;


end.
